#include <iostream>
#include <string>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <map>
#include <random>
#include <openssl/sha.h>
#include <sqlite3.h>
#include <curl/curl.h>
#include <cpp-httplib/httplib.h>

using namespace std;

const string DB_NAME = "user_registration.db";
const string SMTP_SERVER = "smtp.example.com";
const int SMTP_PORT = 587;
const string SMTP_USER = "your_email@example.com";
const string SMTP_PASS = "your_password";
const string FROM_EMAIL = "noreply@example.com";

class DatabaseManager {
    private:
        sqlite3* db;
        
    public:
        DatabaseManager() {
            if (sqlite3_open(DB_NAME.c_str(), &db) != SQLITE_OK) {
                cerr << "无法打开数据库: " << sqlite3_errmsg(db) << endl;
                exit(1);
            }
            
            const char* sql = "CREATE TABLE IF NOT EXISTS users ("
                              "id INTEGER PRIMARY KEY AUTOINCREMENT,"
                              "username TEXT UNIQUE NOT NULL,"
                              "password TEXT NOT NULL,"
                              "email TEXT NOT NULL,"
                              "verification_code TEXT NOT NULL,"
                              "is_verified INTEGER DEFAULT 0,"
                              "registration_time INTEGER NOT NULL,"
                              "expiration_time INTEGER NOT NULL);";
            
            if (sqlite3_exec(db, sql, nullptr, nullptr, nullptr) != SQLITE_OK) {
                cerr << "创建表失败: " << sqlite3_errmsg(db) << endl;
                exit(1);
            }
        }
        
        ~DatabaseManager() {
            sqlite3_close(db);
        }
        
        bool registerUser(const string& username, const string& password, 
                         const string& email, const string& code, time_t expiration) {
            string sql = "INSERT INTO users (username, password, email, verification_code, "
                         "registration_time, expiration_time) VALUES (?, ?, ?, ?, ?, ?);";
            
            sqlite3_stmt* stmt;
            if (sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
                cerr << "准备语句失败: " << sqlite3_errmsg(db) << endl;
                return false;
            }
            
            time_t now = time(nullptr);
            
            sqlite3_bind_text(stmt, 1, username.c_str(), -1, SQLITE_STATIC);
            sqlite3_bind_text(stmt, 2, password.c_str(), -1, SQLITE_STATIC);
            sqlite3_bind_text(stmt, 3, email.c_str(), -1, SQLITE_STATIC);
            sqlite3_bind_text(stmt, 4, code.c_str(), -1, SQLITE_STATIC);
            sqlite3_bind_int64(stmt, 5, now);
            sqlite3_bind_int64(stmt, 6, expiration);
            
            bool success = (sqlite3_step(stmt) == SQLITE_DONE);
            sqlite3_finalize(stmt);
            
            return success;
        }
        
        bool verifyUser(const string& username, const string& code) {
            string sql = "UPDATE users SET is_verified = 1 WHERE username = ? AND "
                         "verification_code = ? AND expiration_time > ? AND is_verified = 0;";
            
            sqlite3_stmt* stmt;
            if (sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
                cerr << "准备语句失败: " << sqlite3_errmsg(db) << endl;
                return false;
            }
            
            time_t now = time(nullptr);
            
            sqlite3_bind_text(stmt, 1, username.c_str(), -1, SQLITE_STATIC);
            sqlite3_bind_text(stmt, 2, code.c_str(), -1, SQLITE_STATIC);
            sqlite3_bind_int64(stmt, 3, now);
            
            bool success = (sqlite3_step(stmt) == SQLITE_DONE);
            sqlite3_finalize(stmt);
            
            return success && sqlite3_changes(db) > 0;
        }
        
        bool isUsernameAvailable(const string& username) {
            string sql = "SELECT 1 FROM users WHERE username = ? AND "
                         "(is_verified = 1 OR expiration_time > ?);";
            
            sqlite3_stmt* stmt;
            if (sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
                cerr << "准备语句失败: " << sqlite3_errmsg(db) << endl;
                return false;
            }
            
            time_t now = time(nullptr);
            
            sqlite3_bind_text(stmt, 1, username.c_str(), -1, SQLITE_STATIC);
            sqlite3_bind_int64(stmt, 2, now);
            
            bool exists = (sqlite3_step(stmt) == SQLITE_ROW);
            sqlite3_finalize(stmt);
            
            return !exists;
        }
        
        void cleanupExpiredRegistrations() {
            string sql = "DELETE FROM users WHERE is_verified = 0 AND expiration_time <= ?;";
            
            sqlite3_stmt* stmt;
            if (sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
                cerr << "准备语句失败: " << sqlite3_errmsg(db) << endl;
                return;
            }
            
            time_t now = time(nullptr);
            sqlite3_bind_int64(stmt, 1, now);
            
            if (sqlite3_step(stmt) != SQLITE_DONE) {
                cerr << "清理过期注册失败: " << sqlite3_errmsg(db) << endl;
            }
            
            sqlite3_finalize(stmt);
        }
};

class EmailService {
    private:
        static size_t payload_source(void* ptr, size_t size, size_t nmemb, void* userp) {
            string* data = static_cast<string*>(userp);
            if (size * nmemb < 1 || data->empty()) return 0;
            
            size_t len = min(size * nmemb, data->size());
            memcpy(ptr, data->c_str(), len);
            data->erase(0, len);
            
            return len;
        }
        
    public:
        bool sendVerificationEmail(const string& to, const string& username, const string& code) {
            CURL* curl = curl_easy_init();
            if (!curl) return false;
            
            string verifyUrl = "http://127.0.0.1/verify?user=" + username + "&code=" + code;
            
            string emailContent = 
                "From: " + FROM_EMAIL + "\r\n"
                "To: " + to + "\r\n"
                "Subject: 请激活您的账户\r\n"
                "Content-Type: text/html; charset=UTF-8\r\n"
                "\r\n"
                "<html><body>"
                "<h2>欢迎注册我们的服务</h2>"
                "<p>请点击以下链接激活您的账户(1小时内有效):</p>"
                "<a href=\"" + verifyUrl + "\">" + verifyUrl + "</a>"
                "</body></html>";
            
            struct curl_slist* recipients = nullptr;
            recipients = curl_slist_append(recipients, to.c_str());
            
            curl_easy_setopt(curl, CURLOPT_URL, (string("smtp://") + SMTP_SERVER + ":" + to_string(SMTP_PORT)).c_str());
            curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM_EMAIL.c_str());
            curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
            curl_easy_setopt(curl, CURLOPT_USERNAME, SMTP_USER.c_str());
            curl_easy_setopt(curl, CURLOPT_PASSWORD, SMTP_PASS.c_str());
            curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
            curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
            curl_easy_setopt(curl, CURLOPT_READDATA, &emailContent);
            curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
            
            CURLcode res = curl_easy_perform(curl);
            bool success = (res == CURLE_OK);
            
            if (!success) {
                cerr << "发送邮件失败: " << curl_easy_strerror(res) << endl;
            }
            
            curl_slist_free_all(recipients);
            curl_easy_cleanup(curl);
            
            return success;
        }
};

class UserService {
    private:
        DatabaseManager db;
        EmailService email;
        
        string generateVerificationCode(const string& username) {
            unsigned char hash[SHA256_DIGEST_LENGTH];
            SHA256_CTX sha256;
            SHA256_Init(&sha256);
            SHA256_Update(&sha256, username.c_str(), username.size());
            SHA256_Final(hash, &sha256);
            
            stringstream ss;
            for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
                ss << hex << setw(2) << setfill('0') << (int)hash[i];
            }
        
            return ss.str().substr(0, 6);
        }
        
    public:
        bool registerUser(const string& username, const string& password, const string& email) {
            db.cleanupExpiredRegistrations();
            
            if (!db.isUsernameAvailable(username)) {
                cerr << "用户名已被占用或正在注册中" << endl;
                return false;
            }
            
            string code = generateVerificationCode(username);
            time_t expiration = time(nullptr) + 3600;

            if (!db.registerUser(username, password, email, code, expiration)) {
                cerr << "注册用户失败" << endl;
                return false;
            }
            
            if (!email.sendVerificationEmail(email, username, code)) {
                cerr << "发送验证邮件失败" << endl;
                return false;
            }
            
            return true;
        }
        
        bool verifyUser(const string& username, const string& code) {
            db.cleanupExpiredRegistrations();
            return db.verifyUser(username, code);
        }
};

class RegistrationServer {
private:
    UserService userService;
    
public:
    void start() {
        httplib::Server svr;
        
        svr.Get("/register", [](const httplib::Request& req, httplib::Response& res) {
            res.set_content(
                "<html><body>"
                "<h1>用户注册</h1>"
                "<form action='/register' method='post'>"
                "用户名: <input type='text' name='username'><br>"
                "密码: <input type='password' name='password'><br>"
                "邮箱: <input type='email' name='email'><br>"
                "<input type='submit' value='注册'>"
                "</form>"
                "</body></html>", 
                "text/html");
        });
        
        svr.Post("/register", [this](const httplib::Request& req, httplib::Response& res) {
            string username = req.get_param_value("username");
            string password = req.get_param_value("password");
            string email = req.get_param_value("email");
            
            if (username.empty() || password.empty() || email.empty()) {
                res.set_content("所有字段都必须填写", "text/plain");
                return;
            }
            
            if (userService.registerUser(username, password, email)) {
                res.set_content("注册成功! 请检查您的邮箱以激活账户", "text/plain");
            } else {
                res.set_content("注册失败", "text/plain");
            }
        });
    
        svr.Get("/verify", [this](const httplib::Request& req, httplib::Response& res) {
            string username = req.get_param_value("user");
            string code = req.get_param_value("code");
            
            if (username.empty() || code.empty()) {
                res.set_content("无效的验证链接", "text/plain");
                return;
            }
            
            if (userService.verifyUser(username, code)) {
                res.set_content("账户激活成功!", "text/plain");
            } else {
                res.set_content("激活失败: 链接无效或已过期", "text/plain");
            }
        });
        
        cout << "服务器启动在 http://127.0.0.1:8080" << endl;
        svr.listen("127.0.0.1", 8080);
    }
};

int main() {
    curl_global_init(CURL_GLOBAL_DEFAULT);
    
    try {
        RegistrationServer server;
        server.start();
    } catch (const exception& e) {
        cerr << "服务器错误: " << e.what() << endl;
        return 1;
    }
    
    curl_global_cleanup();
    return 0;
}